import os
import re
from collections import namedtuple
from typing import Optional
import pysam

BamTview = namedtuple('BamTview', ['reference', 'consensus', 'reads'])


def check_samtools():
    for path in os.environ['PATH'].split(':'):
        if os.path.isdir(path) and 'samtools' in os.listdir(path):
            return
    raise Exception('ERROR: samtools not found, please install it first')


def check_bai(bam: str):
    bai = re.sub(r'bam$', 'bai', bam)
    if not os.path.exists(bai):
        bai = f'{bam}.bai'
        if not os.path.exists(bai):
            raise Exception(f'ERROR: index of {bam} not found, you can run "samtools index {bam}" to build it')


def create_reference(seq: str, cigars: list[str]) -> list[str]:
    bases = list()
    i = 0
    for cigar in cigars:
        if cigar == "I":
            bases.append(' ')
        else:
            bases.append(seq[i])
            i += 1
    return bases


def create_reads(raw_reads: list[str], cigars: list[str]) -> list[list[str]]:
    reads = list()
    for read in raw_reads:
        read = read.upper().replace('*', '-')
        reads.append(read)
    return reads


def tview_bam(bam: str, ref: str, chrom: str, start: int, end: int, extend: int, depth: Optional[int] = None) -> BamTview:
    check_samtools()
    check_bai(bam)
    start -= extend
    end += extend
    width = end - start + 1
    cmd = f'export COLUMNS={width} && samtools tview -d T -p {chrom}:{start} {bam}'
    lines = [line.rstrip('\n') for line in os.popen(cmd).readlines()]
    if depth:
        lines = lines[0:depth + 3]
    reference_seq = pysam.FastaFile(ref).fetch(reference=chrom, start=start - 1, end=end).upper()
    cigars = list(map(lambda s: 'I' if s == '*' else 'M', lines[1]))
    reference = create_reference(seq=reference_seq, cigars=cigars)
    consensus = list(lines[2])
    reads = list(map(lambda s: s.upper().replace('*', '-'), lines[3:]))
    return BamTview(reference=reference, consensus=consensus, reads=reads)
